package com.cola.custSpeechTranscription.api;

import com.cola.custSpeechTranscription.config.CustWebSocketClientConfig;
import com.cola.custSpeechTranscription.model.CustShareSession;
import com.cola.custSpeechTranscription.model.ResetResult;
import com.cola.custSpeechTranscription.model.UserSession;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.BinaryMessage;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.BinaryWebSocketHandler;

import java.io.IOException;
import java.net.URI;
import java.util.concurrent.TimeUnit;

/**
 * @BelongsProject: custSpeechTranscription
 * @BelongsPackage: com.cola.custSpeechTranscription.api
 * @Author: jiangkang
 * @CreateTime: 2025-10-30  14:55
 * @Description: TODO
 * @Version: 1.0
 */
@Component
public class CustAudioWebSocketHandler extends BinaryWebSocketHandler {

    private static final Logger log = LoggerFactory.getLogger("LCAP_EXTENSION_LOGGER");

    @Autowired
    private CustWebSocketClientConfig config;

    @Autowired
    private CustShareSessionManager shareSessionManager;


    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
        // 从请求参数中获取userId
        String userId = getUserIdFromRequest(session);
        if (userId == null || userId.trim().isEmpty()) {
            log.error("[前端连接] 缺少userId参数，关闭连接");
            session.close(CloseStatus.BAD_DATA);
            return;
        }

        log.info("[前端连接] sessionId={}, userId={}，开始建立下游WebSocket连接", session.getId(), userId);

        // 创建或获取用户会话（不自动创建分享）
        UserSession userSession = shareSessionManager.getOrCreateUserSession(userId, session);

        // 创建专属于当前会话的客户端
        CustRemoteWebSocketClient remoteClient = new CustRemoteWebSocketClient(
                new URI(config.getSpeechToTextReqUrl()),
                session, config, shareSessionManager, userId
        );

        // 存入会话属性
        session.getAttributes().put("remoteClient", remoteClient);
        session.getAttributes().put("userId", userId);

        // 建立映射
        shareSessionManager.addSessionToUserMapping(session.getId(), userId);

        log.info("[前端连接存入会话] userId={}");

        // 尝试连接下游服务（不发送任何成功消息）
        try {
            boolean connected = remoteClient.connectBlocking(10, TimeUnit.SECONDS);
            if (connected) {
                log.info("[下游连接成功] userId={}", userId);
                // 不发送任何消息，等待客户端主动查询
            } else {
                log.error("[下游连接失败] userId={}", userId);
                // 不发送任何消息，等待客户端主动查询
            }
        } catch (InterruptedException e) {
            log.error("[下游连接中断] userId={}", userId, e);
            Thread.currentThread().interrupt();
            // 不发送任何消息，等待客户端主动查询
        }
    }

    private String getUserIdFromRequest(WebSocketSession session) {
        try {
            String query = session.getUri().getQuery();
            if (query != null) {
                String[] params = query.split("&");
                for (String param : params) {
                    if (param.startsWith("userId=")) {
                        return param.substring(7);
                    }
                }
            }
        } catch (Exception e) {
            log.error("[获取userId] 从请求中解析userId失败", e);
        }
        return null;
    }

    private CustRemoteWebSocketClient getRemoteClient(WebSocketSession session) {
        return (CustRemoteWebSocketClient) session.getAttributes().get("remoteClient");
    }

    private String getUserIdFromSession(WebSocketSession session) {
        return (String) session.getAttributes().get("userId");
    }

    @Override
    public void handleBinaryMessage(WebSocketSession session, BinaryMessage message) throws Exception {
        byte[] payload = message.getPayload().array();
        String userId = getUserIdFromSession(session);
        log.info("[音频帧] userId={}, sessionId={}，收到前端音频数据 {} 字节",
                userId, session.getId(), payload.length);

        CustRemoteWebSocketClient remoteClient = getRemoteClient(session);
        if (remoteClient != null && remoteClient.isOpen()) {
            remoteClient.sendAudioFrame(payload);
        } else {
            log.info("[音频帧] 下游连接未建立，丢弃音频帧");

            // 通知前端下游连接已断开
            try {
                JSONObject errorMsg = new JSONObject();
                errorMsg.put("type", "downstream_disconnected");
                errorMsg.put("message", "下游服务连接已断开，请重新连接");
                session.sendMessage(new TextMessage(errorMsg.toString()));
            } catch (IOException e) {
                log.error("[发送错误消息] 失败", e);
            }
        }
    }

    @Override
    public void handleTextMessage(WebSocketSession session, TextMessage message) {
        String payload = message.getPayload();
        String userId = getUserIdFromSession(session);
        log.info("[控制消息] userId={}, sessionId={}，收到前端消息：{}", userId, session.getId(), payload);

        CustRemoteWebSocketClient remoteClient = getRemoteClient(session);

        try {
            JSONObject jsonMessage = new JSONObject(payload);
            String type = jsonMessage.optString("type");

            if ("end".equals(type)) {
                log.info("收到结束信号 userId={}", userId);
                if (remoteClient != null && remoteClient.isOpen()) {
                    remoteClient.sendEndFrame();
                } else {
                    log.info("[结束信号] 下游连接未建立，无法发送结束帧");
                }
            } else if ("start_sharing".equals(type)) {
                // 手动创建分享
                handleCreateShare(session, userId, remoteClient);
            } else if ("get_share_info".equals(type)) {
                // 获取分享信息
                handleGetShareInfo(session, userId);
            } else if ("check_downstream".equals(type)) {
                // 检查下游连接状态
                handleCheckDownstream(session, remoteClient);
            } else if ("get_connection_status".equals(type)) {
                // 获取完整连接状态
                handleGetConnectionStatus(session, userId, remoteClient);
            }else if (payload.contains("heartbeat")){
                if (remoteClient != null) {
                    log.info("收到心跳信号");
                    remoteClient.sendHeartbeatFrame();
                }
            }else if ("reset_session".equals(type)) {
                // 重置会话：清除历史数据并停止分享
                handleResetSession(session, userId);
            }
        } catch (Exception e) {
            log.error("[控制消息] 解析消息异常 userId={}", userId, e);
        }
    }

    /**
     * 处理创建分享请求
     */
    private void handleCreateShare(WebSocketSession session, String userId, CustRemoteWebSocketClient remoteClient) {
        try {
            // 检查下游连接状态
            if (remoteClient == null || !remoteClient.isOpen()) {
                JSONObject response = new JSONObject();
                response.put("type", "share_creation_failed");
                response.put("reason", "下游服务连接未建立，无法创建分享");
                session.sendMessage(new TextMessage(response.toString()));
                log.info("[创建分享失败] 下游连接未建立 userId={}", userId);
                return;
            }

            // 创建分享会话
            String shareId = shareSessionManager.createShareSession(userId);

            JSONObject response = new JSONObject();
            response.put("type", "sharing_started");
            response.put("shareId", shareId);
            response.put("message", "分享创建成功");

            session.sendMessage(new TextMessage(response.toString()));
            log.info("[手动创建分享] userId={}, shareId={}", userId, shareId);

        } catch (Exception e) {
            log.error("[创建分享] 异常 userId={}", userId, e);
            try {
                JSONObject response = new JSONObject();
                response.put("type", "share_creation_failed");
                response.put("reason", "创建分享时发生错误: " + e.getMessage());
                session.sendMessage(new TextMessage(response.toString()));
            } catch (IOException ioException) {
                log.error("[发送错误消息] 失败", ioException);
            }
        }
    }

    /**
     * 处理获取分享信息请求
     */
    private void handleGetShareInfo(WebSocketSession session, String userId) {
        try {
            UserSession userSession = shareSessionManager.getUserSession(userId);
            JSONObject response = new JSONObject();
            response.put("type", "share_info");

            if (userSession != null && userSession.getShareSession() != null) {
                CustShareSession shareSession = userSession.getShareSession();
                response.put("shareId", shareSession.getShareId());
                response.put("shareUrl", buildShareUrl(shareSession.getShareId()));
                response.put("viewerCount", shareSession.getViewerCount());
                response.put("status", "active");
                response.put("historyCount", userSession.getTranscripts().size());
            } else {
                response.put("status", "inactive");
                response.put("message", "尚未创建分享");
            }

            session.sendMessage(new TextMessage(response.toString()));
        } catch (IOException e) {
            log.error("[发送分享信息] 失败 userId={}", userId, e);
        }
    }

    /**
     * 处理重置会话请求（清除历史数据 + 停止分享）
     */
    private void handleResetSession(WebSocketSession session, String userId) {
        try {
            // 执行重置操作
            ResetResult result = shareSessionManager.resetUserSession(userId);

            JSONObject response = new JSONObject();
            response.put("type", "session_reset");
            response.put("message", "会话已重置");
            response.put("clearedHistoryCount", result.getClearedHistoryCount());
            response.put("stoppedSharing", result.isStoppedSharing());
            response.put("shareId", result.getShareId());
            response.put("timestamp", System.currentTimeMillis());

            session.sendMessage(new TextMessage(response.toString()));
            log.info("[重置会话] userId={}, 清除历史记录 {} 条, 停止分享: {}",
                    userId, result.getClearedHistoryCount(), result.isStoppedSharing());

        } catch (Exception e) {
            log.error("[重置会话] 异常 userId={}", userId, e);
            try {
                JSONObject response = new JSONObject();
                response.put("type", "reset_session_failed");
                response.put("reason", "重置会话时发生错误: " + e.getMessage());
                session.sendMessage(new TextMessage(response.toString()));
            } catch (IOException ioException) {
                log.error("[发送错误消息] 失败", ioException);
            }
        }
    }

    /**
     * 处理检查下游连接状态请求
     */
    private void handleCheckDownstream(WebSocketSession session, CustRemoteWebSocketClient remoteClient) {
        try {
            JSONObject response = new JSONObject();
            response.put("type", "downstream_status");
            response.put("connected", remoteClient != null && remoteClient.isOpen());
            response.put("timestamp", System.currentTimeMillis());

            session.sendMessage(new TextMessage(response.toString()));
        } catch (IOException e) {
            log.error("[发送下游状态] 失败", e);
        }
    }

    /**
     * 处理获取完整连接状态请求
     */
    private void handleGetConnectionStatus(WebSocketSession session, String userId, CustRemoteWebSocketClient remoteClient) {
        try {
            UserSession userSession = shareSessionManager.getUserSession(userId);

            JSONObject response = new JSONObject();
            response.put("type", "connection_status");
            response.put("userId", userId);
            response.put("sessionId", session.getId());
            response.put("downstreamConnected", remoteClient != null && remoteClient.isOpen());

            // 分享状态
            if (userSession != null && userSession.getShareSession() != null) {
                CustShareSession shareSession = userSession.getShareSession();
                response.put("shareStatus", "active");
                response.put("shareId", shareSession.getShareId());
                response.put("shareUrl", buildShareUrl(shareSession.getShareId()));
                response.put("viewerCount", shareSession.getViewerCount());
                response.put("historyCount", userSession.getTranscripts().size());
            } else {
                response.put("shareStatus", "inactive");
            }

            session.sendMessage(new TextMessage(response.toString()));
        } catch (IOException e) {
            log.error("[发送连接状态] 失败 userId={}", userId, e);
        }
    }

    private String buildShareUrl(String shareId) {
        return "/share/" + shareId;
    }

    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus status){
        String userId = getUserIdFromSession(session);
        log.info("[前端断开] userId={}, sessionId={}，状态={}，开始清理",
                userId, session.getId(), status);
        try{
            // 1. 先关闭下游连接，防止后续操作
            CustRemoteWebSocketClient remoteClient = getRemoteClient(session);
            if (remoteClient != null) {
                remoteClient.close();
                session.getAttributes().remove("remoteClient");
                log.info("[下游连接关闭] userId={}", userId);
            }

            //注释掉更新分享状态的代码，不断开分享 11.3
//            shareSessionManager.updateShareStatus("1",userId,null);

//            // 2. 清理会话管理器
//            if (userId != null) {
//                shareSessionManager.cleanupOnAudioSessionClosed(session);
//
//                // 额外清理session到user的映射
//                shareSessionManager.removeSessionToUserMapping(session.getId());
//            }

            if (userId != null) {
                shareSessionManager.cleanupSessionMappings(session);
            }

            // 3. 清理session属性
            session.getAttributes().remove("userId");

            log.info("[前端断开清理完成] userId={}, sessionId={}", userId, session.getId());
        }catch (Exception e) {
            log.error("[前端断开清理异常] userId={}, sessionId={}", userId, session.getId(), e);
        }
    }
}